//有 n 个气球，编号为0 到 n - 1，每个气球上都标有一个数字，这些数字存在数组 nums 中。 
//
// 现在要求你戳破所有的气球。戳破第 i 个气球，你可以获得 nums[i - 1] * nums[i] * nums[i + 1] 枚硬币。 这里的 i -
// 1 和 i + 1 代表和 i 相邻的两个气球的序号。如果 i - 1或 i + 1 超出了数组的边界，那么就当它是一个数字为 1 的气球。 
//
// 求所能获得硬币的最大数量。 
//
// 
//示例 1：
//
// 
//输入：nums = [3,1,5,8]
//输出：167
//解释：
//nums = [3,1,5,8] --> [3,5,8] --> [3,8] --> [8] --> []
//coins =  3*1*5    +   3*5*8   +  1*3*8  + 1*8*1 = 167 
//
// 示例 2： 
//
// 
//输入：nums = [1,5]
//输出：10
// 
//
// 
//
// 提示： 
//
// 
// n == nums.length 
// 1 <= n <= 300 
// 0 <= nums[i] <= 100 
// 
// Related Topics 数组 动态规划 👍 1039 👎 0

package leetcode.editor.cn;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

class BurstBalloons {
    public static void main(String[] args) {
        Solution solution = new BurstBalloons().new Solution();
        solution.maxCoins(new int[]{3, 1, 5, 8});
    }

    //leetcode submit region begin(Prohibit modification and deletion)
    class Solution {
        /*public int maxCoins(int[] nums) {
            int coinNum = 0;
            List<Integer> list = new ArrayList<>();
            for (int i = 0; i < nums.length; i++) {
                list.add(nums[i]);
            }

            while (!list.isEmpty()) {
                int minIndex = 0, min = Integer.MAX_VALUE;
                for (int i = 0; i < list.size(); i++) {
                    if (list.get(i) <= min) {
                        min = list.get(i);
                        minIndex = i;
                    }
                }

                int temp = (((minIndex - 1) < 0 ? 1 : list.get(minIndex - 1))
                        * ((minIndex + 1) >= list.size() ? 1 : list.get(minIndex + 1))
                        * list.get(minIndex));
                coinNum += temp;
                list.remove(minIndex);
            }

            return coinNum;
        }*/

        /*public int maxCoins(int[] nums) {
            int n = nums.length;
            int[] newNums = new int[nums.length + 2];
            newNums[0] = 1;
            newNums[n + 1] = 1;
            for (int i = 0; i < n; i++) {
                newNums[i + 1] = nums[i];
            }
            int[][] dp = new int[n + 2][n + 2];

            // 表示开区间长度
            for (int len = 3; len <= n + 2; len++) {
                // 开区间的最左边
                for (int i = 0; i <= n + 2 - len; i++) {
                    int res = 0;
                    // 中间索引
                    for (int j = i + 1; j < i + len - 1; j++) {
                        int left = dp[i][j];
                        int right = dp[j][i + len - 1];
                        res = Math.max(res, left + newNums[i] * newNums[j] * newNums[i + len - 1] + right);
                    }
                    dp[i][i + len - 1] += res;
                }
            }

            return dp[0][n + 1];
        }*/

        // https://mp.weixin.qq.com/s/I0yo0XZamm-jMpG-_B3G8g
        public int maxCoins(int[] nums) {
            int n = nums.length;
            int[] array = new int[n + 2];
            // 将首尾加入虚拟气球
            array[0] = 1;
            array[n + 1] = 1;
            for (int i = 0; i < n; i++) {
                array[i + 1] = nums[i];
            }

            // 表示在(i,j)区间戳爆所有气球的最大分数
            int[][] dp = new int[n + 2][n + 2];
            // 从下到上
            for (int i = n; i >= 0; i--) {
                // 从左到右
                for (int j = i + 1; j <= n + 1; j++) {
                    for (int k = i + 1; k < j; k++) {
                        dp[i][j] = Math.max(dp[i][j], dp[i][k] + dp[k][j] + array[k] * array[i] * array[j]);
                    }
                }
            }

            return dp[0][n + 1];
        }
    }
//leetcode submit region end(Prohibit modification and deletion)

}
